home *** CD-ROM | disk | FTP | other *** search
- /* ICMP-related user commands
- * Copyright 1991 Phil Karn, KA9Q
- */
- /* Mods by PA0GRI */
- #include "global.h"
- #include "commands.h"
- #ifndef MSDOS
- #include <time.h>
- #endif
- #include "icmp.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: icmpcmd.c,v 1.20 1997/08/19 01:19:22 root Exp root $";
- #endif
-
- static int pingcmd (int argc, char *argv[], void *p);
- static int doicmpec (int argc, char *argv[], void *p);
- static int doicmpstat (int argc, char *argv[], void *p);
- static int doicmptr (int argc, char *argv[], void *p);
- static int doicmptimeexceed (int argc, char *argv[], void *p);
- static void pingtx (int s, void *ping1, void *p);
- static void pinghdr (struct session * sp, struct ping * ping, time_t * start);
-
- #ifdef CATALOG
- #include "catalog.h"
-
- #define CAT icmpcmd_catalog
-
- #define tracingis __STR(0)
- #define tracemodes __STR(1)
- #define echostr __STR(2)
- #define ttlstr __STR(3)
- #define resolving __STR(4)
- #define pinging __STR(5)
- #define pingaborted __STR(6)
- #define pingtimeout __STR(7)
- #define pinghdrstr1 __STR(8)
- #define pinghdrstr2 __STR(9)
-
- #else /* CATALOG */
- static const char tracingis[] = "ICMP Tracing is %d\n";
- static const char tracemodes[] = "Trace modes are: 0|1|2\n";
- static const char echostr[] = "ICMP echo response accept";
- static const char ttlstr[] = "Ttl time exceed reply";
- static const char resolving[] = "Resolving %s... ";
- static const char pinging[] = "Pinging %s... Press <CR> to abort...\n";
- static const char pingaborted[] = "%s: ping aborted by user after %d seconds\n";
- static const char pingtimeout[] = "%s: no response after 120 seconds\n";
- static const char pinghdrstr1[] = "Pinging %s (%s); data %d interval %lu ms:\n since %s";
- static const char pinghdrstr2[] = " sent rcvd %% rtt avg rtt mdev received\n";
-
- #endif /* CATALOG */
-
-
- static const char statstr1[] = "(%2u)%-20s%10lu";
- static const char statstr2[] = " (%2u)%-20s%10lu\n";
- static const char pingfmt[] = "%10lu %10lu %5lu %10lu %10lu %10lu %8.8s\n";
- static const char pingrtt[] = "%s: rtt %lu\n";
-
- static int currentPing = 0;
-
-
- static struct cmds Icmpcmds[] =
- {
- { "echo", doicmpec, 0, 0, NULLCHAR},
- { "status", doicmpstat, 0, 0, NULLCHAR},
- { "timeexceed", doicmptimeexceed, 0, 0, NULLCHAR},
- { "trace", doicmptr, 0, 0, NULLCHAR},
- { NULLCHAR, NULL, 0, 0, NULLCHAR},
- };
-
-
- int Icmp_trace;
- static int Icmp_echo = 1;
-
-
- int
- doicmp (argc, argv, p)
- int argc;
- char *argv[];
- void *p;
- {
- return subcmd (Icmpcmds, argc, argv, p);
- }
-
-
- static int
- doicmpstat (argc, argv, p)
- int argc OPTIONAL;
- char *argv[] OPTIONAL;
- void *p OPTIONAL;
- {
- register int i;
- int lim;
-
- /* Note that the ICMP variables are shown in column order, because
- * that lines up the In and Out variables on the same line
- */
- lim = NUMICMPMIB / 2;
- for (i = 1; i <= lim; i++) {
- tprintf (statstr1, i, Icmp_mib[i].name, Icmp_mib[i].value.integer);
- tprintf (statstr2, i + lim, Icmp_mib[i + lim].name, Icmp_mib[i + lim].value.integer);
- }
- return 0;
- }
-
-
- static int
- doicmptr (argc, argv, p)
- int argc;
- char *argv[];
- void *p OPTIONAL;
- {
- if (argc < 2) {
- tprintf (tracingis, Icmp_trace);
- return 0;
- }
- switch (argv[1][0]) {
- case '0':
- case '1':
- case '2':
- Icmp_trace = atoi (argv[1]);
- break;
- default:
- tputs (tracemodes);
- return -1;
- }
-
- return 0;
- }
-
-
- static int
- doicmpec (argc, argv, p)
- int argc;
- char *argv[];
- void *p OPTIONAL;
- {
- return setbool (&Icmp_echo, echostr, argc, argv);
- }
-
-
- int Icmp_timeexceed = 1;
- static int
- doicmptimeexceed (argc, argv, p)
- int argc;
- char *argv[];
- void *p OPTIONAL;
- {
- return setbool (&Icmp_timeexceed, ttlstr, argc, argv);
- }
-
-
- /* Send ICMP Echo Request packets */
- static int
- pingcmd (argc, argv, p)
- int argc;
- char *argv[];
- void *p OPTIONAL;
- {
- struct proc *pinger = NULLPROC; /* Transmit process */
- struct sockaddr_in from;
- struct icmp icmp;
- struct mbuf *bp;
- int32 timestamp, rtt, abserr;
- int s, fromlen;
- struct ping ping;
- struct session *sp = (struct session *) 0;
- time_t starttime, thetime;
- char *cptr;
- int usesession = 0;
-
- /* Make sure this is a 'one-shot- ping
- * if not coming from the console - WG7J
- */
- if (argc > 3)
- if (Curproc->input != Command->input)
- return 0;
-
- memset ((char *) &ping, 0, sizeof (ping));
- /* Allocate a session descriptor if this comes from console */
- if (Curproc->input == Command->input) {
- usesession = 1;
- if ((sp = ping.sp = newsession (argv[1], PING, 0)) == NULLSESSION) {
- tputs (TooManySessions);
- return 1;
- }
- }
- if ((s = socket (AF_INET, SOCK_RAW, ICMP_PTCL)) == -1) {
- tputs (Nosock);
- if (usesession) {
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- }
- return 1;
- }
- if (usesession && sp != NULLSESSION)
- sp->s = s;
-
- tprintf (resolving, argv[1]);
-
- if ((ping.target = resolve (argv[1])) == 0) {
- tprintf (Badhost, argv[1]);
- if (usesession) {
- (void) keywait (NULLCHAR, 1);
- freesession (sp);
- }
- return 1;
- }
- if (argc > 2)
- ping.len = (int16) atoi (argv[2]);
-
- if (argc > 3)
- ping.interval = atol (argv[3]);
-
-
- /* Optionally ping a range of IP addresses */
- if (argc > 4)
- ping.incflag = 1;
-
- if (ping.interval != 0)
- pinger = newproc ("pingtx", 300, pingtx, s, &ping, NULL, 0);
- else {
- /* One shot ping; let echo_proc hook handle response.
- * An ID of MAXINT16 will not be confused with a legal socket
- * number, which is used to identify repeated pings
- */
- if (usesession) {
- pingem (s, ping.target, 0, MAXINT16, ping.len);
- freesession (sp);
- } else {
- int k;
-
- tprintf (pinging, argv[1]);
- usflush (Curproc->output);
- currentPing = Curproc->output;
- pingem (s, ping.target, 0, MAXINT16, ping.len);
- for (k = 0; k < 120; k++) {
- if (!currentPing)
- break;
- if (socklen (Curproc->input, 0)) {
- (void) recv_mbuf (Curproc->input, NULL, 0, NULLCHAR, 0); /* flush */
- tprintf (pingaborted, argv[1], k);
- break;
- }
- (void) kpause (1000L);
- }
- currentPing = 0;
- if (k == 120)
- tprintf (pingtimeout, argv[1]);
- close_s (s);
- }
- return 0;
- }
- (void) time (&starttime);
- /* Now collect the replies */
- pinghdr (sp, &ping, &starttime);
- for ( ; ; ) {
- fromlen = sizeof (from);
- if (recv_mbuf (s, &bp, 0, (char *) &from, &fromlen) == -1)
- break;
- (void) ntohicmp (&icmp, &bp);
- if (icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s) {
- /* Ignore other people's responses */
- free_p (bp);
- continue;
- }
- /* Get stamp */
- if (pullup (&bp, (unsigned char *) ×tamp, sizeof (timestamp))
- != sizeof (timestamp)) {
- /* The timestamp is missing! */
- free_p (bp); /* Probably not necessary */
- continue;
- }
- free_p (bp);
-
- ping.responses++;
-
- /* Compute round trip time, update smoothed estimates */
- rtt = msclock () - timestamp;
- if (rtt < 0)
- rtt = 0;
- abserr = (rtt > ping.srtt) ? (rtt - ping.srtt) : (ping.srtt - rtt);
-
- if (ping.responses == 1) {
- /* First response, base entire SRTT on it */
- ping.srtt = rtt;
- ping.mdev = 0;
- } else { /*lint -save -e704 */
- ping.srtt = (7 * ping.srtt + rtt + 4) >> 3;
- ping.mdev = (3 * ping.mdev + abserr + 2) >> 2;
- } /*lint -restore */
- if ((ping.responses % 20) == 0)
- pinghdr (sp, &ping, &starttime);
- (void) time (&thetime);
- cptr = ctime (&thetime);
- tprintf (pingfmt, ping.sent, ping.responses,
- (ping.responses * 100 + ping.sent / 2) / ping.sent,
- rtt, ping.srtt, ping.mdev, &cptr[11]);
- }
- if (pinger != NULLPROC)
- killproc (pinger);
- freesession (sp);
- return 0;
- }
-
-
- int
- doping (argc, argv, p)
- int argc;
- char *argv[];
- void *p;
- {
- char **pargv;
- int i;
-
- if (Curproc->input == Command->input) {
- /* Make private copy of argv and args,
- * spawn off subprocess and return.
- */
- pargv = (char **) callocw ((unsigned) argc + 1, sizeof (char *));
-
- for (i = 0; i < argc; i++)
- pargv[i] = strdup (argv[i]);
- pargv[i] = NULL;
- (void) newproc ("ping", 512, (void (*)(int, void *, void *)) pingcmd, argc, (void *) pargv, p, 1);
- } else
- (void) pingcmd (argc, argv, p);
- return 0;
- }
-
-
- static void
- pinghdr (sp, ping, start)
- struct session *sp;
- struct ping *ping;
- time_t *start;
- {
- tprintf (pinghdrstr1, sp->name, inet_ntoa (ping->target), ping->len, ping->interval, ctime (start));
- tprintf (pinghdrstr2);
- }
-
-
- void
- echo_proc (source, dest, icmp, bp)
- uint32 source;
- uint32 dest OPTIONAL;
- struct icmp *icmp;
- struct mbuf *bp;
- {
- int32 timestamp, rtt;
-
- if (Icmp_echo && icmp->args.echo.id == MAXINT16
- && pullup (&bp, (unsigned char *) ×tamp, sizeof (timestamp))
- == sizeof (timestamp)) {
- /* Compute round trip time */
- rtt = msclock () - timestamp;
- usprintf ((currentPing) ? currentPing : Command->output, pingrtt, inet_ntoa (source), rtt);
- currentPing = 0;
- }
- free_p (bp);
- }
-
-
- /* Ping transmit process. Runs until killed */
- static void
- pingtx (s, ping1, p)
- int s; /* Socket to use */
- void *ping1;
- void *p OPTIONAL;
- {
- struct ping *ping;
-
- ping = (struct ping *) ping1;
- ping->sent = 0;
- if (ping->incflag) {
- for (;;) {
- pingem (s, ping->target++, 0, MAXINT16, ping->len);
- ping->sent++;
- (void) kpause (ping->interval);
- }
- } else {
- for (;;) {
- pingem (s, ping->target, (int16) ping->sent++, (int16) s, ping->len);
- (void) kpause (ping->interval);
- }
- }
- }
-
-
- /* Send ICMP Echo Request packet */
- void
- pingem (s, target, seq, id, len)
- int s; /* Raw socket on which to send ping */
- uint32 target; /* Site to be pinged */
- int16 seq; /* ICMP Echo Request sequence number */
- int16 id; /* ICMP Echo Request ID */
- int16 len; /* Length of optional data field */
- {
- struct mbuf *data;
- struct mbuf *bp;
- struct icmp icmp;
- struct sockaddr_in to;
- int32 theclock;
-
- theclock = msclock ();
- data = ambufw ((int16) (len + sizeof (theclock)));
- data->cnt = len + sizeof (theclock);
- /* Set optional data field, if any, to all 55's */
- if (len != 0)
- memset (data->data + sizeof (theclock), 0x55, (size_t) len);
-
- /* Insert timestamp and build ICMP header */
- memcpy (data->data, (char *) &theclock, sizeof (theclock));
- icmpOutEchos++;
- icmpOutMsgs++;
- icmp.type = ICMP_ECHO;
- icmp.code = 0;
- icmp.args.echo.seq = seq;
- icmp.args.echo.id = id;
- if ((bp = htonicmp (&icmp, data)) == NULLBUF) {
- free_p (data);
- return;
- }
- to.sin_family = AF_INET;
- to.sin_addr.s_addr = target;
- (void) send_mbuf (s, bp, 0, (char *) &to, sizeof (to));
- }
-